package com.boom.monitor.util;

import com.boom.monitor.VO.jmx.BeanAttributeInfo;
import com.boom.monitor.VO.jmx.BeanAttributeValue;
import com.boom.monitor.VO.jmx.BeanInfo;
import com.boom.monitor.config.JmxConnectorInstance;

import javax.management.*;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.CompositeDataSupport;
import javax.management.openmbean.TabularDataSupport;
import javax.management.remote.JMXConnector;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.*;

/**
 * @author:yzw
 * @Date:2021/3/1 下午4:43
 * @desc:
 * @version:1.0
 */
public class JmxUtils {

	public static BeanInfo getObjectNameProperties(String fullName) {
		JmxConnectorInstance commonConfig = JmxConnectorInstance.INSTANCE;
		JMXConnector connector = commonConfig.getJmxConnector();
		BeanInfo beanInfo = new BeanInfo();
		List<BeanAttributeInfo> beanAttributeInfos = new ArrayList<>();
		try {
			if (connector != null) {
				MBeanServerConnection msc = connector.getMBeanServerConnection();
				ObjectName queryObjectName = new ObjectName(fullName);
				Set<ObjectName> objectNames = msc.queryNames(queryObjectName, null);
				if (objectNames != null) {
					for (ObjectName o : objectNames) {
						dealObjectNames(msc, o, beanAttributeInfos, beanInfo);
					}
					beanInfo.setBeanAttributeInfos(beanAttributeInfos);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return beanInfo;
	}

	private static void dealObjectNames(MBeanServerConnection msc, ObjectName o
			, List<BeanAttributeInfo> beanAttributeInfos, BeanInfo beanInfo) throws
			IntrospectionException, ReflectionException, InstanceNotFoundException, IOException {
		MBeanInfo mBeanInfo = msc.getMBeanInfo(o);
		MBeanAttributeInfo[] mBeanAttributeInfos = mBeanInfo.getAttributes();
		MBeanOperationInfo[] mBeanOperationInfos = mBeanInfo.getOperations();
		MBeanNotificationInfo[] mBeanNotificationInfos = mBeanInfo.getNotifications();
		for (MBeanAttributeInfo mBeanAttributeInfo : mBeanAttributeInfos) {
			boolean isReadable = mBeanAttributeInfo.isReadable();
			Object attribute;
			if (isReadable) {
				try {
					attribute = msc.getAttribute(o, mBeanAttributeInfo.getName());
				} catch (Exception e) {
					attribute = "不可用";
				}
			} else {
				attribute = "不可读";
			}
			BeanAttributeInfo beanAttributeInfo = new BeanAttributeInfo();
			beanAttributeInfo.setName(mBeanAttributeInfo.getName());
			beanAttributeInfo.setAttributeInfo(mBeanAttributeInfo);
			BeanAttributeValue beanAttributeValue = new BeanAttributeValue();
			if ("javax.management.openmbean.CompositeData".equals(mBeanAttributeInfo.getType()) && mBeanAttributeInfo.isReadable()) {
				SortedMap<String, Object> map = analyzeCompositeData(attribute);
				beanAttributeValue.setCompositeData(true);
				beanAttributeValue.setData(map);
			} else if ("[Ljavax.management.openmbean.CompositeData;".equals(mBeanAttributeInfo.getType()) && mBeanAttributeInfo.isReadable()) {
				List<SortedMap<String, Object>> mapList = new ArrayList<>();
				CompositeData[] compositeDataArray = (CompositeData[]) attribute;
				for (CompositeData compositeData : compositeDataArray) {
					SortedMap<String, Object> map = analyzeCompositeData(compositeData);
					mapList.add(map);
				}
				beanAttributeValue.setCompositeData(true);
				beanAttributeValue.setData(mapList);
			} else if ("javax.management.openmbean.TabularData".equals(mBeanAttributeInfo.getType())) {
				List<SortedMap<String, Object>> mapList = new ArrayList<>();
				TabularDataSupport tabularDataSupport = (TabularDataSupport) attribute;
				for (Map.Entry<Object, Object> entry : tabularDataSupport.entrySet()) {
					SortedMap<String, Object> map = analyzeCompositeData(entry.getValue());
					SortedMap<String, Object> normalMap = new TreeMap<>();
					String key = null;
					if (map != null) {
						key = (String) map.getOrDefault("key", "");
					}
					Object value = null;
					if (map != null) {
						value = map.getOrDefault("value", "");
					}
					normalMap.put("name", key);
					normalMap.put("value", value);
					mapList.add(normalMap);
				}
				beanAttributeValue.setCompositeData(true);
				beanAttributeValue.setData(mapList);
			} else {
				beanAttributeValue.setCompositeData(false);
				beanAttributeValue.setData(attribute);
			}
			beanAttributeInfo.setValue(beanAttributeValue);
			beanAttributeInfos.add(beanAttributeInfo);
		}
		beanInfo.setOperationInfos(mBeanOperationInfos);
		beanInfo.setNotificationInfos(mBeanNotificationInfos);
	}

	@SuppressWarnings("unchecked")
	private static SortedMap<String, Object> analyzeCompositeData(Object compositeData) {
		try {
			if (compositeData instanceof CompositeDataSupport) {
				CompositeDataSupport support = (CompositeDataSupport) compositeData;
				Field field = support.getClass().getDeclaredField("contents");
				field.setAccessible(true);
				Object map = field.get(support);
				return (SortedMap<String, Object>) map;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
}
